#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import logging
from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, QLabel,
    QComboBox, QLineEdit, QCheckBox
)
from PyQt5.QtCore import Qt, pyqtSignal

from app.ui.components.styled_label import StyledLabel
from app.services.service_locator import ServiceLocator
from app.services.config_service import IConfigService

class VoiceModule(QWidget):
    """
    音色配置模块类，包含音色相关的UI和功能
    """
    
    # 定义信号
    voice_updated = pyqtSignal(str, object)  # 音色更新信号
    
    def __init__(self, parent=None):
        """
        初始化音色管理模块
        
        @param parent: 父窗口
        """
        super().__init__(parent)
        
        # 初始化日志
        self.logger = logging.getLogger(self.__class__.__name__)
        
        # 初始化成员变量
        self.config_path = None
        self.host_voice_combo = None
        self.assist_voice_combo = None
        
        # 获取配置服务
        self.config_service = ServiceLocator.get(IConfigService)
        
        # 初始化UI
        self._init_ui()
    
    def _init_ui(self):
        """
        初始化UI
        """
        # 创建主布局
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(10, 10, 10, 10)
        main_layout.setSpacing(10)
        
        # 创建音色配置组
        self._create_voice_config_group(main_layout)
    
    def _create_voice_config_group(self, parent_layout):
        """
        创建音色配置组
        
        @param parent_layout: 父布局
        """
        # 主播和助播音色行
        voice_row = QHBoxLayout()
        voice_row.setSpacing(15)  # 设置组件之间的间距
        
        # 主播音色标签
        host_voice_label = StyledLabel("主播音色:", size=StyledLabel.SMALL)
        host_voice_label.setAlignment(Qt.AlignVCenter)
        
        # 主播音色下拉框
        self.host_voice_combo = QComboBox()
        self.host_voice_combo.setMinimumHeight(28)  # 设置最小高度
        self.host_voice_combo.currentTextChanged.connect(self._on_host_voice_changed)
        
        # 助播音色标签
        assist_voice_label = StyledLabel("助播音色:", size=StyledLabel.SMALL)
        assist_voice_label.setAlignment(Qt.AlignVCenter)
        
        # 助播音色下拉框
        self.assist_voice_combo = QComboBox()
        self.assist_voice_combo.setMinimumHeight(28)  # 设置最小高度
        self.assist_voice_combo.currentTextChanged.connect(self._on_assist_voice_changed)
        self.assist_voice_combo.setEnabled(False)  # 设置为不可编辑，因为助播功能尚未开发
        
        # 助播音色右侧输入框
        self.assist_voice_input = QLineEdit()
        self.assist_voice_input.setMinimumHeight(28)  # 设置最小高度
        self.assist_voice_input.setPlaceholderText("TTS服务URL")
        
        # 如果配置服务可用，加载已保存的TTS URL
        if self.config_service:
            tts_url = self.config_service.get("tts.url", "http://127.0.0.1:8080")
            self.assist_voice_input.setText(tts_url)
        
        # 为输入框添加回车键事件处理
        self.assist_voice_input.returnPressed.connect(self._on_tts_url_entered)
        
        # 加载音色选项
        self._load_voice_options()
        
        # 添加主播音色到水平布局
        voice_row.addWidget(host_voice_label)
        voice_row.addWidget(self.host_voice_combo, 1)  # 下拉框占据剩余空间
        
        # 添加间隔
        voice_row.addSpacing(30)
        
        # 添加助播音色到水平布局
        voice_row.addWidget(assist_voice_label)
        voice_row.addWidget(self.assist_voice_combo, 1)  # 下拉框占据剩余空间
        
        # 添加助播音色右侧输入框
        voice_row.addWidget(self.assist_voice_input, 1)  # 输入框占据剩余空间
        
        # 添加到主布局
        parent_layout.addLayout(voice_row)
        
        # 添加一个新行，包含"自动添加.pt后缀"选项
        suffix_row = QHBoxLayout()
        suffix_row.setSpacing(15)  # 设置组件之间的间距
        
        # 自动添加.pt后缀勾选框
        self.auto_add_pt_suffix = QCheckBox("自动添加.pt后缀")
        self.auto_add_pt_suffix.setChecked(True)  # 默认选中
        self.auto_add_pt_suffix.stateChanged.connect(self._on_auto_add_pt_suffix_changed)
        
        # 添加空白占位
        suffix_row.addSpacing(20)
        
        # 添加勾选框
        suffix_row.addWidget(self.auto_add_pt_suffix)
        
        # 添加弹性空间
        suffix_row.addStretch(1)
        
        # 添加到主布局
        parent_layout.addLayout(suffix_row)
    
    def _on_tts_url_entered(self):
        """
        处理TTS URL输入框回车事件
        """
        # 获取输入的URL
        url = self.assist_voice_input.text().strip()
        
        if not url:
            self.logger.warning("输入的TTS URL为空，将使用默认值")
            url = "http://127.0.0.1:8080"
            self.assist_voice_input.setText(url)
        
        self.logger.info(f"设置TTS URL: {url}")
        
        # 保存到配置服务
        if self.config_service:
            # 统一更新两种格式的配置键
            # 1. 更新app.config使用的格式
            self.config_service.set("tts.url", url)
            
            # 2. 同时更新直接配置格式
            tts_config = self.config_service.get("tts", {})
            if isinstance(tts_config, dict):
                tts_config["url"] = url
                self.config_service.set("tts", tts_config)
            
            # 保存配置
            self.config_service.save_config()
            self.logger.info(f"已保存TTS URL配置: {url}")
            
            # 获取音频服务并更新配置
            from app.services.audio_service import IAudioService
            audio_service = ServiceLocator.get(IAudioService)
            if audio_service:
                # 同时使用两种格式的配置键进行配置
                audio_service.configure({
                    "tts_url": url,
                    "tts": {"url": url}
                })
                self.logger.info("已更新音频服务TTS URL配置")
                
                # 验证配置是否生效
                self._verify_tts_connection(audio_service, url)
            else:
                self.logger.warning("无法获取音频服务，TTS URL配置可能不会立即生效")
            
            # 获取语音服务并更新配置
            from app.services.speech_service import ISpeechService
            speech_service = ServiceLocator.get(ISpeechService)
            if speech_service:
                # 同时使用两种格式的配置键进行配置
                speech_service.configure({
                    "tts_url": url,
                    "url": url
                })
                self.logger.info("已更新语音服务TTS URL配置")
            else:
                self.logger.warning("无法获取语音服务，TTS URL配置可能不会立即生效")
                
            # 强制重新加载AppConfig
            from app.config.app_config import AppConfig
            app_config = AppConfig.get_instance()
            app_config.reload()
            self.logger.info("已重新加载全局AppConfig配置")
        else:
            self.logger.warning("配置服务不可用，无法保存TTS URL配置")
    
    def _verify_tts_connection(self, audio_service, url):
        """
        验证TTS连接是否生效
        
        @param audio_service: 音频服务实例
        @param url: 要验证的TTS URL
        """
        try:
            # 尝试调用音频服务的连接检测方法
            if hasattr(audio_service, '_check_tts_connection'):
                is_connected = audio_service._check_tts_connection()
                if is_connected:
                    self.logger.info(f"TTS服务连接测试成功: {url}")
                    # 这里可以添加UI反馈，比如临时显示一个成功消息
                    from PyQt5.QtWidgets import QToolTip
                    QToolTip.showText(self.assist_voice_input.mapToGlobal(self.assist_voice_input.rect().bottomRight()), 
                                     f"TTS服务连接成功: {url}", self)
                else:
                    self.logger.warning(f"TTS服务连接测试失败: {url}")
                    from PyQt5.QtWidgets import QToolTip
                    QToolTip.showText(self.assist_voice_input.mapToGlobal(self.assist_voice_input.rect().bottomRight()), 
                                     f"TTS服务连接失败: {url}", self)
            else:
                self.logger.warning("音频服务没有TTS连接检测方法")
        except Exception as e:
            self.logger.error(f"验证TTS连接时发生错误: {str(e)}")
            import traceback
            self.logger.error(traceback.format_exc())
    
    def _load_voice_options(self):
        """
        从配置路径的音色管理目录中加载音色选项
        """
        if not self.config_path:
            self.logger.warning("配置路径未设置，无法加载音色选项")
            return
        
        # 构建音色管理目录路径
        voice_dir = os.path.join(self.config_path, "音色管理")
        self.logger.info(f"音色管理目录路径: {voice_dir}")
        
        # 检查目录是否存在
        if not os.path.exists(voice_dir):
            self.logger.info(f"音色管理目录不存在，创建目录: {voice_dir}")
            try:
                os.makedirs(voice_dir, exist_ok=True)
            except Exception as e:
                self.logger.error(f"创建音色管理目录失败: {str(e)}")
                return
        
        # 清空下拉框
        self.host_voice_combo.clear()
        self.assist_voice_combo.clear()
        
        # 获取目录中的.pt音色文件
        try:
            all_files = os.listdir(voice_dir)
            
            files = [f for f in all_files if f.endswith('.pt')]
            self.logger.info(f"找到 {len(files)} 个.pt音色文件")
            
            # 提取音色名称列表
            voice_names = [os.path.splitext(file)[0] for file in files]
            
            # 对音色名称进行排序
            sorted_voice_names = sorted(voice_names)
            self.logger.info(f"按名称排序后的音色列表: {sorted_voice_names}")
            
            # 添加排序后的音色文件到下拉框
            for voice_name in sorted_voice_names:
                self.host_voice_combo.addItem(voice_name)
                self.assist_voice_combo.addItem(voice_name)
            
            self.logger.info(f"已加载 {len(sorted_voice_names)} 个音色选项")
            
            # 注意：移除了自动设置默认选中项的代码，让音色选择完全由set_voice_config方法控制
        except Exception as e:
            self.logger.error(f"加载音色选项失败: {str(e)}")
            import traceback
            self.logger.error(traceback.format_exc())
    
    def _on_host_voice_changed(self, value):
        """
        主播音色改变事件处理
        
        @param value: 主播音色
        """
        self.voice_updated.emit("host_voice", value)
    
    def _on_assist_voice_changed(self, value):
        """
        助播音色改变事件处理
        
        @param value: 助播音色
        """
        self.voice_updated.emit("assist_voice", value)
    
    def _on_auto_add_pt_suffix_changed(self, state):
        """
        处理自动添加.pt后缀选项变更
        
        @param state: 选中状态
        """
        is_checked = (state == Qt.Checked)
        self.logger.info(f"设置自动添加.pt后缀: {is_checked}")
        
        # 触发音色更新信号
        self.voice_updated.emit("add_pt_suffix", is_checked)
        
        # 如果配置服务可用，直接保存配置
        if self.config_service:
            self.config_service.set("speech.add_pt_suffix", is_checked)
            self.config_service.save_config()
    
    def set_config_path(self, path):
        """
        设置配置路径
        
        @param path: 配置路径
        """
        if not path:
            self.logger.warning("配置路径为空，无法加载音色选项")
            return
            
        # 检查路径是否存在
        if not os.path.exists(path):
            self.logger.warning(f"配置路径不存在: {path}")
            try:
                os.makedirs(path, exist_ok=True)
                self.logger.info(f"已创建配置路径: {path}")
            except Exception as e:
                self.logger.error(f"创建配置路径失败: {str(e)}")
                return
        
        # 如果配置路径没有变化，不需要重新加载
        if self.config_path == path:
            self.logger.info(f"配置路径未变化，跳过加载: {path}")
            return
            
        # 更新配置路径
        self.config_path = path
        self.logger.info(f"设置配置路径: {path}")
        
        # 检查音色管理目录
        voice_dir = os.path.join(path, "音色管理")
        if not os.path.exists(voice_dir):
            self.logger.info(f"音色管理目录不存在，将创建: {voice_dir}")
            try:
                os.makedirs(voice_dir, exist_ok=True)
                self.logger.info(f"已创建音色管理目录: {voice_dir}")
            except Exception as e:
                self.logger.error(f"创建音色管理目录失败: {str(e)}")
        
        # 加载音色选项，但不设置默认值
        self._load_voice_options_without_defaults()
    
    def _load_voice_options_without_defaults(self):
        """
        从配置路径的音色管理目录中加载音色选项，但不设置默认值
        """
        if not self.config_path:
            self.logger.warning("配置路径未设置，无法加载音色选项")
            return
        
        # 构建音色管理目录路径
        voice_dir = os.path.join(self.config_path, "音色管理")
        self.logger.info(f"音色管理目录路径: {voice_dir}")
        
        # 检查目录是否存在
        if not os.path.exists(voice_dir):
            self.logger.info(f"音色管理目录不存在，创建目录: {voice_dir}")
            try:
                os.makedirs(voice_dir, exist_ok=True)
            except Exception as e:
                self.logger.error(f"创建音色管理目录失败: {str(e)}")
                return
        
        # 保存当前选中的音色
        current_host_voice = None
        current_assist_voice = None
        if self.host_voice_combo.count() > 0:
            current_host_voice = self.host_voice_combo.currentText()
            self.logger.info(f"保存当前主播音色: {current_host_voice}")
        if self.assist_voice_combo.count() > 0:
            current_assist_voice = self.assist_voice_combo.currentText()
            self.logger.info(f"保存当前助播音色: {current_assist_voice}")
        
        # 清空下拉框，但不触发信号
        self.host_voice_combo.blockSignals(True)
        self.assist_voice_combo.blockSignals(True)
        self.host_voice_combo.clear()
        self.assist_voice_combo.clear()
        
        # 获取目录中的.pt音色文件
        try:
            all_files = os.listdir(voice_dir)
            
            files = [f for f in all_files if f.endswith('.pt')]
            self.logger.info(f"找到 {len(files)} 个.pt音色文件")
            
            # 提取音色名称列表
            voice_names = [os.path.splitext(file)[0] for file in files]
            
            # 对音色名称进行排序
            sorted_voice_names = sorted(voice_names)
            self.logger.info(f"按名称排序后的音色列表: {sorted_voice_names}")
            
            # 添加排序后的音色文件到下拉框
            for voice_name in sorted_voice_names:
                self.host_voice_combo.addItem(voice_name)
                self.assist_voice_combo.addItem(voice_name)
            
            self.logger.info(f"已加载 {len(sorted_voice_names)} 个音色选项")
            
            # 如果之前有选中的音色，尝试恢复
            if current_host_voice and self.host_voice_combo.findText(current_host_voice) >= 0:
                self.host_voice_combo.setCurrentText(current_host_voice)
                self.logger.info(f"恢复主播音色: {current_host_voice}")
            
            if current_assist_voice and self.assist_voice_combo.findText(current_assist_voice) >= 0:
                self.assist_voice_combo.setCurrentText(current_assist_voice)
                self.logger.info(f"恢复助播音色: {current_assist_voice}")
                
            # 恢复信号连接
            self.host_voice_combo.blockSignals(False)
            self.assist_voice_combo.blockSignals(False)
        except Exception as e:
            # 恢复信号连接
            self.host_voice_combo.blockSignals(False)
            self.assist_voice_combo.blockSignals(False)
            self.logger.error(f"加载音色选项失败: {str(e)}")
            import traceback
            self.logger.error(traceback.format_exc())
    
    def set_voice_config(self, config):
        """
        设置音色配置
        
        @param config: 音色配置字典
        """
        self.logger.info(f"设置音色配置: {config}")
        
        # 检查音色选项是否已加载
        if self.host_voice_combo.count() == 0 or self.assist_voice_combo.count() == 0:
            self.logger.info("音色选项未加载，尝试加载音色选项")
            self._load_voice_options_without_defaults()
            
            # 如果加载后仍然没有音色选项，记录警告
            if self.host_voice_combo.count() == 0 or self.assist_voice_combo.count() == 0:
                self.logger.warning("无法加载音色选项，请检查配置路径和音色文件")
                return
        
        # 记录当前可用的音色选项
        host_voices = [self.host_voice_combo.itemText(i) for i in range(self.host_voice_combo.count())]
        assist_voices = [self.assist_voice_combo.itemText(i) for i in range(self.assist_voice_combo.count())]
        
        # 设置主播音色
        host_voice = config.get("host_voice", "")
        actual_host_voice = None  # 用于记录实际设置的音色
        
        if host_voice:
            self.logger.info(f"设置主播音色: {host_voice}")
            # 尝试查找完全匹配的音色
            index = self.host_voice_combo.findText(host_voice)
            if index >= 0:
                # 断开信号连接，避免触发不必要的更新
                self.host_voice_combo.blockSignals(True)
                self.host_voice_combo.setCurrentIndex(index)
                self.host_voice_combo.blockSignals(False)
                actual_host_voice = host_voice
                self.logger.info(f"已设置主播音色: {host_voice}, 索引: {index}")
            else:
                # 如果找不到完全匹配，尝试部分匹配
                partial_match_index = -1
                for i in range(self.host_voice_combo.count()):
                    item_text = self.host_voice_combo.itemText(i)
                    if host_voice in item_text or item_text in host_voice:
                        partial_match_index = i
                        break
                
                if partial_match_index >= 0:
                    # 断开信号连接，避免触发不必要的更新
                    self.host_voice_combo.blockSignals(True)
                    self.host_voice_combo.setCurrentIndex(partial_match_index)
                    self.host_voice_combo.blockSignals(False)
                    actual_host_voice = self.host_voice_combo.itemText(partial_match_index)
                    self.logger.info(f"已设置主播音色(部分匹配): {actual_host_voice}, 索引: {partial_match_index}")
                else:
                    # 如果找不到匹配的音色，保持当前选择
                    self.logger.warning(f"未找到配置的主播音色: {host_voice}，保持当前选择")
        # 移除自动选择第一个音色的代码
        
        # 设置助播音色
        assist_voice = config.get("assist_voice", "")
        actual_assist_voice = None  # 用于记录实际设置的音色
        
        if assist_voice:
            self.logger.info(f"设置助播音色: {assist_voice}")
            # 尝试查找完全匹配的音色
            index = self.assist_voice_combo.findText(assist_voice)
            if index >= 0:
                # 断开信号连接，避免触发不必要的更新
                self.assist_voice_combo.blockSignals(True)
                self.assist_voice_combo.setCurrentIndex(index)
                self.assist_voice_combo.blockSignals(False)
                actual_assist_voice = assist_voice
                self.logger.info(f"已设置助播音色: {assist_voice}, 索引: {index}")
            else:
                # 如果找不到完全匹配，尝试部分匹配
                partial_match_index = -1
                for i in range(self.assist_voice_combo.count()):
                    item_text = self.assist_voice_combo.itemText(i)
                    if assist_voice in item_text or item_text in assist_voice:
                        partial_match_index = i
                        break
                
                if partial_match_index >= 0:
                    # 断开信号连接，避免触发不必要的更新
                    self.assist_voice_combo.blockSignals(True)
                    self.assist_voice_combo.setCurrentIndex(partial_match_index)
                    self.assist_voice_combo.blockSignals(False)
                    actual_assist_voice = self.assist_voice_combo.itemText(partial_match_index)
                    self.logger.info(f"已设置助播音色(部分匹配): {actual_assist_voice}, 索引: {partial_match_index}")
                else:
                    # 如果找不到匹配的音色，保持当前选择
                    self.logger.warning(f"未找到配置的助播音色: {assist_voice}，保持当前选择")
        # 移除自动选择第一个音色的代码
        
        # 设置是否自动添加.pt后缀选项
        add_pt_suffix = config.get("add_pt_suffix", True)
        if hasattr(self, 'auto_add_pt_suffix'):
            self.auto_add_pt_suffix.setChecked(add_pt_suffix)
        
        # 手动触发音色更新信号，确保配置被保存
        if actual_host_voice:
            self.voice_updated.emit("host_voice", actual_host_voice)
        if actual_assist_voice:
            self.voice_updated.emit("assist_voice", actual_assist_voice) 